package com.gitee.cashzhang27.test.cloud.oauth.resource.server.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

/**
 * @author Cash Zhang
 * @version v1.0
 * @since 2019/02/09 12:32
 */
public class AdditionalTokenServices extends DefaultTokenServices {

  @Autowired
  private TokenStore tokenStore;

  @Autowired
  private ClientDetailsService clientDetailsService;

  @Override
  public OAuth2Authentication loadAuthentication(String accessTokenValue)
      throws AuthenticationException, InvalidTokenException {
    OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
    if (accessToken == null) {
      throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
    } else if (accessToken.isExpired()) {
      tokenStore.removeAccessToken(accessToken);
      throw new InvalidTokenException("Access token expired: " + accessTokenValue);
    }

    OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
    if (result == null) {
      // in case of race condition
      throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
    }
    if (clientDetailsService != null) {
      String clientId = result.getOAuth2Request().getClientId();
      try {
        clientDetailsService.loadClientByClientId(clientId);
      } catch (ClientRegistrationException e) {
        throw new InvalidTokenException("Client not valid: " + clientId, e);
      }
    }
    result.setDetails(accessToken.getAdditionalInformation());
    return result;
  }
}
